#include "Server.h"
#include "../base/Adder/AdderFactory.h"
#include "../base/Adder/PictureAdder.h"
#include "../base/Codec/Codec.h"

#include <muduo/net/Endian.h>
#include <assert.h>
#include <muduo/base/Logging.h>



Server::Server(muduo::net::EventLoop* loop, const muduo::net::InetAddress& listenAddr)
    : loop_(loop),
      server_(loop, listenAddr, "Server"),
      factory_(new AbstractAdderFactory)
{
    server_.setConnectionCallback(
        std::bind(&Server::onConnection, this, muduo::_1));
    server_.setMessageCallback(
        std::bind(&Server::onMessage, this, muduo::_1, muduo::_2, muduo::_3));
}

void Server::onConnection(const muduo::net::TcpConnectionPtr& conn)
{
    LOG_INFO << "Server - " << conn->peerAddress().toIpPort() << " -> "
             << conn->localAddress().toIpPort() << " is " 
             << (conn->connected() ? "UP" : "DOWN");
}

void Server::onMessage(const muduo::net::TcpConnectionPtr& conn,
                            muduo::net::Buffer* buf, muduo::Timestamp time)
{
    uint32_t flag = muduo::net::sockets::networkToHost32(*static_cast<const uint32_t*>((const void*)(buf->peek())));
    buf->retrieve(static_cast<size_t>(sizeof(uint32_t)));
    uint32_t all_size = muduo::net::sockets::networkToHost32(*static_cast<const uint32_t*>((const void*)(buf->peek())));
    buf->retrieve(static_cast<size_t>(sizeof(uint32_t)));
    std::string oriStream;
    int tempErrno;
    while (oriStream.size() < all_size) {
      oriStream += buf->retrieveAllAsString();
      buf->readFd(conn->getConnectionSocket(), &tempErrno);
    }

    IAdder* adder;
    ICodec* codec = new Codec;
    if (flag == static_cast<uint32_t>(1))
      adder = factory_->createTextAdder();
    else if (flag == static_cast<uint32_t>(2))
      adder = factory_->createPictureAdder();
    else 
      fprintf(stderr, "Server::onMessage(): flag error\n");
    adder->setInitialContent(oriStream);
    std::string retImageName = adder->addMark();
    assert(!retImageName.empty());
    codec->encode(retImageName);
    conn->send(codec->getResultContentEncode());
}
